/*
 * Copyright (c) 2011 Ondrej Lapacek
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

/**
 * @author      Ondrej Lapacek
 * @version     1.0, 09/12/11
 * @since       1.0
 */

package cz.muni.fi.android.assistivecamera.camera;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Environment;
import android.util.Log;

public class CameraShutter {
	private Camera mCamera;
	private boolean isShutterReady = false;
	private File pic = null; 
	private JSONArray json = null;
	private List<JSONObject> lst = new ArrayList<JSONObject>();
	
	private static final String TAG = "Camera Shutter";	
	
    public CameraShutter(Camera camera, Context context) {
        mCamera = camera;
        
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_AUTOFOCUS))
        	mCamera.autoFocus(mCameraAutofocusCallback);
        else 
        	camera.takePicture(shutterCallback, rawCallback, jpegCallback);
    }


	public boolean isReady() {
        return isShutterReady;
    }
    
    private Camera.AutoFocusCallback mCameraAutofocusCallback = new Camera.AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
        	camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
    };
    
    ShutterCallback shutterCallback = new ShutterCallback() {
		public void onShutter() {
			Log.d(TAG, "onShutter'd");
		}
	};

	/** Handles data for raw picture */
	PictureCallback rawCallback = new PictureCallback() {
		public void onPictureTaken(byte[] data, Camera camera) {
			if( data != null) {
				Log.d(TAG, "CameraView::onPictureTaken(), data length: " + data.length);
				
			}
			else {
				Log.d(TAG, "CameraView::onPictureTaken(), data is null! ");
			}
		}
	};

	/** Handles data for jpeg picture */
	PictureCallback jpegCallback = new PictureCallback() {
		public void onPictureTaken(byte[] data, Camera camera) {
			String state = Environment.getExternalStorageState();
			
			if( Environment.MEDIA_MOUNTED.equals(state) && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) != true) {
				File path = new File(Environment.getExternalStorageDirectory() + "/DCIM/BlindPhoto/");
				path.mkdirs();
				try {
					String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
					
					pic = new File(path, "IMG_" + timeStamp + ".jpg");
					OutputStream os = new FileOutputStream(pic);
					os.write(data);
					os.close();
					
					try {
						// attempt to get a Camera instance
						mCamera.startPreview();
			        } catch (Exception e){
			        	Log.e(TAG, "Camera is not available (in use or does not exist)", e);
			        }
			    	mCamera.startPreview();
				} catch (FileNotFoundException e) {
					Log.e(TAG, "CameraView::savePictureToMemCard: io exception", e);
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					
				}
			}
			else {
				Log.e(TAG, "CameraView::savePictureToMemCard(): no media mounted! ");			
			}
			
			isShutterReady = true;
		}
	};
	
	public void deleteLastPicture() {
        pic.delete();
    }
	
	public void loadExifData(Map<String, Object> map) {
		lst.add(new JSONObject(map));
    }
	/*
	public void loadExifData(Map<String,JSONObject> data){
		lst.add(new JSONObject(data))
	}
	*/
	public void loadExifData(String name,JSONObject obj){
		Map<String,JSONObject> object = new HashMap<String,JSONObject>();
		object.put(name,obj);
		lst.add(new JSONObject(object));
	}
	public void saveExifData() {
		json = new JSONArray(lst);
		String exifData = toBaseCharacters(json.toString());
		
		Log.d(TAG, " PATH picture " + pic.getAbsolutePath());
		Log.d(TAG, " exifData " + exifData);

		String state = Environment.getExternalStorageState();
		if( Environment.MEDIA_MOUNTED.equals(state) && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) != true) {
			File path = new File(Environment.getExternalStorageDirectory() + "/DCIM/BlindPhoto/");
			path.mkdirs();
			try {
			    String nameOfFile = pic.getName().replaceFirst("[.][^.]+$", "");
			    File metaData = new File(path, nameOfFile);
			    FileWriter fw = new FileWriter(metaData);
			    BufferedWriter os = new BufferedWriter(fw);
			    os.write(exifData);
				os.close();
			} catch (FileNotFoundException e) {
				Log.e(TAG, "CameraView::savePictureToMemCard: io exception", e);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		else {
			Log.e(TAG, "CameraView::savePictureToMemCard(): no media mounted! ");			
		}	
        	
        /*
        ExifInterface ei = new ExifInterface(pic.getAbsolutePath()); 
        ei.setAttribute("UserComment", exifData);
		ei.saveAttributes(); */
		
		Log.e(TAG, " JSON " + json.toString());
	}
	
    private static final String toBaseCharacters(final String sText) {
    	// convert the input string to a character array
    	char[] chars = sText.toCharArray();

    	StringBuilder sb = new StringBuilder();
    	for (int i = 0; i < chars.length; i++)
    	{
    	    int unipoint = Character.codePointAt(chars, i);
    	    if ((unipoint < 32) || (unipoint > 127)) {
    	        StringBuilder hexString = new StringBuilder();
    	        for (int k = 0; k < 4; k++) { // 4 times to build a 4-digit hex
    	            hexString.insert(0, Integer.toHexString(unipoint % 16));
    	            unipoint = unipoint / 16;
    	        }
    	        sb.append("\\u"+hexString);
    	    } else {
    	        sb.append(chars[i]);
    	    }
    	}

    	// display the ASCII encoded string
    	return sb.toString();
    }
}
